﻿#
# Permet d'enclencher le retrait d'une solution WSP.
#
function RetractSolution
{
	param
	(
		[Parameter(ValueFromPipeline=$true)]
		[string] $name,
		[Parameter(ValueFromPipeline=$true)]
		[int] $maxWaitDurationInSeconds
	)
	process
	{
		# Récupération de la solution au sein de la ferme
	    $solution = Get-SPSolution $name -ErrorAction SilentlyContinue
	    
		if ($solution -ne $null) 
		{
			# Retrait de la solution
			if ($solution.Deployed)
			{
				write-host "	> Retrait de la solution $name" -f white -NoNewline	
				
				try
				{
					# Uninstall
					if ($solution.ContainsWebApplicationResource)
					{
						$solution | Uninstall-SPSolution -AllWebApplications -Confirm:$false
					} 
					else 
					{
						$solution | Uninstall-SPSolution -Confirm:$false
					}
					
					# Attente
					$checkDuration = ( ($maxWaitDurationInSeconds -ne $null) -and ($maxWaitDurationInSeconds -gt 0))
					$waitTime = $maxWaitDurationInSeconds
					$wait = ((Get-SPSolution $solution.Name).Deployed -eq $true)
					while($wait)
					{
			            write-host -NoNewLine .
			            Start-Sleep -Seconds 2
						
						if($checkDuration)
						{
							$waitTime -= 2
						}
						$wait = ( ((Get-SPSolution $solution.Name).Deployed -eq $true) -and ($waitTime -gt 0) )
					}
					
					Write-Host " OK" -ForegroundColor Green
				}
				catch
				{
					Write-Host " KO" -ForegroundColor Red
					Write-Host $_ -ForegroundColor Red
				}
			}
			else
			{
				write-host "	> La solution $name n'est pas déployée" -f white
			}
		}
	}
}

#
# Permet de supprimer une solution du magasin de solutions de ferme
#
function RemoveSolution
{
	param
	(
		[Parameter(ValueFromPipeline=$true)]
		[string] $name
	)
	process
	{
		$solution = Get-SPSolution $name -ErrorAction SilentlyContinue
		if($solution -ne $null)
		{
			try
			{
				WaitForSolutionJobToFinish $solution.Name
				Remove-SPSolution $name -Confirm:$false -Force
				do 
				{ 
					write-host -NoNewLine .
					Start-Sleep 2
				}
				while ((Get-SPSolution $name -ErrorAction SilentlyContinue) -ne $null)
				Write-Host " OK" -ForegroundColor Green
			}
			catch
			{
				Write-Host $_ -ForegroundColor Red
			}
		}
		else
		{
			Write-Host
		}
	}
}

#
# Permet d'ajouter une solution au magasin de solutions de ferme
#
function AddSolution
{
	param
	(
		[Parameter(ValueFromPipeline=$true)]
		[string]$packagesPath,
		[Parameter(ValueFromPipeline=$true)]
		[string]$name
	)
	process
	{
		$wspFile = Get-Item -Path $packagesPath$name -ErrorAction SilentlyContinue
		if ($wspFile -eq $null) 
		{
			write-host "	> Package non trouvée."
			return;
		}
		else
		{
			Add-SPSolution -LiteralPath $packagesPath$name -Confirm:$false
		}
	}
}

#
# Permet d'installer chacun des packages WSP selon le paramétrage définit dans le fichier de configuration.
#
function InstallSolution
{
	param
	(
	[Parameter(ValueFromPipeline=$true)]
	[string]$packagesPath, 
	[Parameter(ValueFromPipeline=$true)]
	[string]$name, 
	[Parameter(ValueFromPipeline=$true)]
	[bool]$gac, 
	[Parameter(ValueFromPipeline=$true)]
	[bool]$cas, 
	[Parameter(ValueFromPipeline=$true)]
	[string[]]$webApps = @()
	)
	process
	{
		# On regarde si le fichier WSP existe au sein du répertoire [ Packages ] avant de réaliser l'opération
		$wspFile = Get-Item -Path $packagesPath$name -ErrorAction SilentlyContinue
		if ($wspFile -eq $null) {
			write-host "	> Package non trouvée."
			return;
		}
		
	    $solution = Get-SPSolution $name -ErrorAction SilentlyContinue
	    	
	    #Deploy the solution
	    if (!$solution.ContainsWebApplicationResource) 
		{
			write-host "	> Déploiement dans la ferme en cours." -f white -NoNewline
			try
			{
				$solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -Confirm:$false -Force

				# Attente du déploiement de la solution
				WaitForSolutionJobToFinish $name
				
				
				Write-Host " OK" -ForegroundColor Green
			}
			catch
			{
				Write-Host " KO" -ForegroundColor Red
				Write-Host $_ -ForegroundColor Red
			}
		}
		else 
		{
			if ($webApps -eq $null -or $webApps.Length -eq 0) 
			{
				Write-Warning "The solution $name contains web application resources but no web applications were specified to deploy to."
				return
			}
			
			write-host "	> Déploiement dans les Web Applications." -f white
			foreach($webApp in $webApps)
			{
				$vWebAppUrl = $webApp
				
				write-host "	Déploiement dans l'application web [ $vWebAppUrl ] en cours." -NoNewline
				try
				{
					$solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -WebApplication $vWebAppUrl -Confirm:$false -Force
					
					# Attente du déploiement de la solution
					WaitForSolutionJobToFinish $name
				
					Write-Host " OK" -ForegroundColor Green
				}
				catch
				{
					Write-Host " KO" -ForegroundColor Red
					Write-Host $_ -ForegroundColor Red
				}
				Write-Host
			}
		}
	}
}

#
# Permet d'attendre que le déploiement d'une solution WSP soit réalisée.
#
function WaitForJobToFinish
{
	param
	(
		[Parameter(ValueFromPipeline=$true)]
		[string] $SolutionFileName,
		[Parameter(ValueFromPipeline=$true)]
		[int] $maxWaitDurationInSeconds
	)
	process
	{ 
		# On vérifie si une durée maximale d'attente a été positionnée
		# On positionne la valeur de comparaison en fonction de cette dérification
		$checkDuration = (($maxWaitDurationInSeconds -ne $null) -and ($maxWaitDurationInSeconds -gt 0))
		if($checkDuration)
		{
			$waitTime = $maxWaitDurationInSeconds
		}
		else
		{
			$waitTime = 1
		}
		
		# On vérifie l'existence d'un job de déploiement
	    $JobName = "*solution-deployment*$SolutionFileName*"
	    $job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
	    if ($job -eq $null) 
	    {
	        write-host " Timer job non trouvé"
	    }
	    else
	    {
	        $JobFullName = $job.Name
			$wait = ((Get-SPTimerJob $JobFullName) -ne $null)
			
			# On boucle tant que
			#		Un job de déploiement existe pour le composant 
			#		Le temps max n'est pas atteint
	        while($wait) 
	        {
	            write-host -NoNewLine .
	            Start-Sleep -Seconds 2
				
				# Vérification de la condition de sortie de boucle
				if($checkDuration)
				{
					$waitTime -= 2
				}
				$wait = ( ((Get-SPTimerJob $JobFullName) -ne $null) -and ($waitTime -gt 0) )
	        }
	    }
	}
}

#
# Attente de la fin d'existence d'un Job associé à un WSP
#
function WaitForSolutionJobToFinish
{
	param
	(
		[Parameter(ValueFromPipeline=$true)]
		[string] $name,
		[Parameter(ValueFromPipeline=$true)]
		[int] $maxWaitDurationInSeconds
	)
	process
	{
		# On vérifie si une durée maximale d'attente a été positionnée
		# On positionne la valeur de comparaison en fonction de cette dérification
		$checkDuration = (($maxWaitDurationInSeconds -ne $null) -and ($maxWaitDurationInSeconds -gt 0))
		if($checkDuration)
		{
			$waitTime = $maxWaitDurationInSeconds
		}
		else
		{
			$waitTime = 1
		}

		# Si la solution existe, on traite l'attente
		if($solution -ne $null)
		{			
			$wait = ((Get-SPSolution | ?{$_.Name -eq $name}).JobExists -eq $true)
			
			# On boucle tant que
			#		La solution a un job de déploiement
			#		Le temps max n'est pas atteint
			while($wait)
			{
				Write-Host "." -NoNewline
				Start-Sleep -Seconds 2
				
				# Vérification de la condition de sortie de boucle
				if($checkDuration)
				{
					$waitTime -= 2
				}
				$wait = ( ((Get-SPSolution | ?{$_.Name -eq $name}).JobExists -eq $true) -and ($waitTime -gt 0) )
			}
		}
	}
}

#
# Attente de la fin de tous les jobs associé à des WSP
#
function WaitAllSolutionJobsToBeFinished
{
	Write-Host "Attente de la fin de tous les déploiements de solutions " -NoNewline
	
	# Attente en utilisant les solutions comme point d'entrée
	# while( (Get-SPSolution | ?{$_.JobExists -eq $true}).Count -gt 0 )
	# {
		# Write-Host "." -NoNewline
		# Start-Sleep -Seconds 5
	# }
	
	# Attente en utilisant les Jobs comme point d'entrée
	# while( (Get-SPTimerJob | ?{ $_.Name -like "*solution-deployment*" }).Count -gt 0)
	# {
		# Write-Host "." -NoNewline
		# Start-Sleep -Seconds 5
	# }
	
	foreach ($sol in Get-SPSolution)
	{
		$res = WaitForSPSolutionJobToComplete -solutionName $sol.Name
	}

	Write-Host " OK" -ForegroundColor Green
}

function WaitForSPSolutionJobToComplete([string]$solutionName) {     
	$solution = Get-SPSolution -Identity $solutionName -ErrorAction SilentlyContinue       
	
	if ($solution)     
	{   
		$doW = $false
		
		if ($solution.JobExists)     
		{             
			Write-Host -NoNewLine "Waiting for timer job to complete for solution '$solutionName'."
			$doW = $true
		}                   
		
		# Check if there is a timer job still associated with this solution and wait until it has finished         
		while ($solution.JobExists)         
		{             
			$jobStatus = $solution.JobStatus                           
			# If the timer job succeeded then proceed             
			if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Succeeded)             
			{                 
				Write-Host "Solution '$solutionName' timer job suceeded"                
				return $true            
			}                           
			# If the timer job failed or was aborted then fail             
			if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Aborted -or $jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Failed)             
			{                 
				Write-Host "Solution '$solutionName' has timer job status '$jobStatus'."                
				return $false            
			}                           
			# Otherwise wait for the timer job to finish             
			Write-Host -NoNewLine "."    
			$doW = $true
			Sleep 1         
		}                   
		# Write a new line to the end of the '.....'      
		if ($doW){
			Write-Host    
		}
	}           
	return $true
}

# 
# Affichage des Jobs de déploiement en cours sur la base de la liste des TimerJobs
#
function ViewDeploymentJobs
{
		$Host.ui.rawui.ForegroundColor = "DarkRed"

		$JobName = "*solution-deployment**"
	    Get-SPTimerJob | ?{ $_.Name -like $JobName } | ft Name
		Get-SPSolution | ?{$_.JobExists -eq $true} | ft Name
		
		$Host.ui.rawui.ForegroundColor = "Gray"
}

#
# Permet de vérifier si une solution est déployée sur une application web spécifique.
#
function IsSolutionDeployedForWebApp
{
	param
	(
	[Parameter(ValueFromPipeline=$true)]
	[string]$webAppUrl, 
	[Parameter(ValueFromPipeline=$true)]
	[string]$solutionName
	)
	process
	{
		$solution = Get-SPSolution $solutionName
		if ($solution -eq $null) {
		}
		else
		{	
			$solution.DeployedWebApplications | ForEach-Object {
				if ($_.Url.ToLower().Equals($webAppUrl) -or $_.Url.ToUpper().Equals($webAppUrl))
				{
					write-host "			Solution déployée sur l'application web." -f Yellow
					Start-Sleep 15
					return $true
				}
			}
		}
		return $false
	}
}

#
# Permet de redémarrer les services OWSTimer sur les frontaux de la ferme	
#
function RestartFarmOWSTimers
{
	# Attente de la fin des jobs de déploiement
	WaitAllSolutionJobsToBeFinished
	
	# Redémarrage de OWSTimer
	$farm = Get-SPFarm
	$farm.TimerService.Instances | foreach {
		try {
			$_.Stop();
		} catch {
			Sleep 60
			$_.Stop();
		}
		$_.Start();
	}
}
